/*
@STI LICENSE
(C) 2006-2008 Universit�t Innsbruck.

This file is part of myOntology.

myOntologyis free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

myOntologyis distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with myOntology.  If not, see <http://www.gnu.org/licenses/>.

@STI LICENSE */
package view.servlets;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import model.Labels;
import model.Vocabulary;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.myontology.controller.AttributeHolder;
import org.myontology.controller.WebAttributeHolder;
import org.myontology.logging.ElementLogging;
import org.myontology.logging.ElementLoggingProvider;
import org.myontology.users.Login;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.OWL;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;
import org.openrdf.sail.memory.MemoryStore;

import controller.HelperFunctions;
import controller.elementMapper.ClassMapper;
import controller.elementMapper.Mapper;
import controller.elementMapper.PropertyMapper;
import controller.elementMapper.UriAlreadyExistsException;
import controller.sesameDataConnector.AbstractDataConnector;

/**
 * Servlet implementation class for Servlet: Import
 *
 */
 public class Import extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
	 
	 public static Logger logger = Logger.getLogger(Import.class);
	 
   static final long serialVersionUID = 16L;

	public static final URI ELEMENTISIMPORTED = new URIImpl("http://myontology.org/v0#elementIsImported");
	public static final URI SUBCLASSIMPORTED = new URIImpl("http://myontology.org/v0#subclassOfIsImported");
	public static final URI SAMECLASSASIMPORTED = new URIImpl("http://myontology.org/v0#sameClassAsIsImported");
	public static final URI SAMEPROPERTYASIMPORTED = new URIImpl("http://myontology.org/v0#samePropertyAsIsImported");
	
	
	private ElementLogging elementLogging;
	
    /* (non-Java-doc)
	 * @see javax.servlet.http.HttpServlet#HttpServlet()
	 */
	public Import() {
		super();
	}   	

	
	/* (non-Java-doc)
	 * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		AttributeHolder attributes = new WebAttributeHolder(request);
		elementLogging = (ElementLogging)new ElementLoggingProvider().create(attributes);
		elementLogging.init();
		
		
		
		
		
		if ( !Login.LOGGED_IN.getValue(request) ) {			
			response.sendRedirect( request.getContextPath() + "/login");
			return;
		}
		
		String ret = null;

		URI toImportUri = null;
		RepositoryConnection memoryStoreConnection = null;

		HttpSession session = request.getSession();	
		boolean lock = session.getAttribute("lockOntology")!=null;
		Repository toImportRepository = (Repository)session.getAttribute( "toImportRepository" );
		HashMap<URI, URI> hashMap = (HashMap<URI, URI>)session.getAttribute( "HashMap" ); // contains relations from toImportUri (key) to in system imported uri (value)
		URI ontologyModuleUri = null;
		URI type = null;
		
		try {
			
			if( hashMap==null ) {
				
				hashMap = new HashMap<URI, URI>();
			}

			memoryStoreConnection = toImportRepository.getConnection();
			RepositoryConnection connection = AbstractDataConnector.getConnection(); // connection to the system-Repository

			if( request.getParameter( "toimporturi" )!=null  ) { // user_had_to_change_label

				String newLabel = request.getParameter( "newlabel" );
				String tmp = request.getParameter( "toimporturi" );
				toImportUri = new URIImpl( tmp );
				
				type = getType( memoryStoreConnection, toImportUri );
				
				
				
				if( type.equals( OWL.ONTOLOGY ) ) {
					importOntologyModule( connection, memoryStoreConnection, toImportUri, newLabel, hashMap,attributes );
					
				}
				else if( type.equals( OWL.CLASS ) || type.equals( RDFS.CLASS ) ) {

					ontologyModuleUri = hashMap.get( getOntologyUri( memoryStoreConnection ) );
					importClass( connection, memoryStoreConnection, toImportUri, newLabel, hashMap, ontologyModuleUri,attributes  );
				}
				else if( type.equals( OWL.DATATYPEPROPERTY ) ) {

					importProperty( connection, memoryStoreConnection, toImportUri, newLabel, hashMap, Vocabulary.DATATYPEPROPERTY,attributes  );
				}
				else if( type.equals( OWL.OBJECTPROPERTY ) ) {

					importProperty( connection, memoryStoreConnection, toImportUri, newLabel, hashMap, Vocabulary.OBJECTPROPERTY,attributes  );
				}
			}

			
			// import remaining data:
			type = OWL.ONTOLOGY;
			toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			// es sollte nur 1 OntologyModule im memoryStore vorkommen!
			if( toImportUri!=null ) {
				
				importOntologyModule( connection, memoryStoreConnection, toImportUri, getLabelForURI( memoryStoreConnection, toImportUri ), hashMap,attributes  );
			}

			ontologyModuleUri = hashMap.get( getOntologyUri( memoryStoreConnection ) );

			//TODO create Lock here!!!!!
			
			if (lock && toImportUri!=null) {
				RepositoryConnection con = AbstractDataConnector.getConnection();
				con.add(ontologyModuleUri,Vocabulary.ISLOCKED,ontologyModuleUri);
			}
			
			type = OWL.CLASS;
			toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			while( toImportUri!=null ) { 
				
				importClass( connection, memoryStoreConnection, toImportUri, getLabelForURI(  memoryStoreConnection, toImportUri ), hashMap, ontologyModuleUri,attributes  );
				toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			}

			toImportUri = getUnmarkedSubClassOf( memoryStoreConnection );
			while( toImportUri!=null ) { 
				
				importSubClassOf( connection, memoryStoreConnection, toImportUri, hashMap );
				toImportUri = getUnmarkedSubClassOf( memoryStoreConnection );
			}
			

			toImportUri = getUnmarkedSameClassAs( memoryStoreConnection );
			while( toImportUri!=null ) { 
				
				importSameClassAs( connection, memoryStoreConnection, toImportUri, hashMap );
				toImportUri = getUnmarkedSameClassAs( memoryStoreConnection );
			}
			

			type = OWL.DATATYPEPROPERTY;
			toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			while( toImportUri!=null ) { 
				
				importProperty( connection, memoryStoreConnection, toImportUri, getLabelForURI(  memoryStoreConnection, toImportUri ), hashMap, Vocabulary.DATATYPEPROPERTY,attributes  );
				toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			}
			type = OWL.OBJECTPROPERTY;
			toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			while( toImportUri!=null ) { 
				
				importProperty( connection, memoryStoreConnection, toImportUri, getLabelForURI(  memoryStoreConnection, toImportUri ), hashMap, Vocabulary.OBJECTPROPERTY,attributes  );
				toImportUri = getUnmarkedElement( memoryStoreConnection, type );
			}
			

			toImportUri = getUnmarkedSamePropertyAs( memoryStoreConnection );
			while( toImportUri!=null ) { 
				
				importSamePropertyAs( connection, memoryStoreConnection, toImportUri, hashMap );
				toImportUri = getUnmarkedSamePropertyAs( memoryStoreConnection );
			}
			
		}
		catch( UriAlreadyExistsException e ) {
			 // a form should be printed where the user can change the label
			
			ret =
				"<p>Tried to import element with URI '"+ toImportUri +"' and rdf:type '" + type + "'</p>" +
				"<div class=\"error\">There exists an element with the same label. Change the label to proceed!</div>" +
				"</p>" +
				"<p>" +
				"New label " +
				"<input" +
				" onkeypress=\"if((event.keyCode==13)){document.getElementById('continuebutton').click();}\" " +
				" type=\"text\" style=\"width: 300px;\" id=\"newLabelInput\" value=\"" + StringEscapeUtils.escapeHtml( getLabelForURI( memoryStoreConnection, toImportUri) ) + "\" /> " +
				
				"<input type=\"hidden\" id=\"toImportUri\" value=\"" + StringEscapeUtils.escapeHtml( toImportUri.stringValue() ) + "\" />" +
				"<input type=\"button\" id=\"continuebutton\" onclick=\"submitChangedLabel(document.getElementById('newLabelInput').value,document.getElementById('toImportUri').value)\" value=\"continue\" />" +
				"</p>";
			
		}
		catch( Exception e ) {
			ret = 
				"<p>Tried to import element with URI '"+ toImportUri +"' and rdf:type '" + type + "'</p>" +
				"<p>An unknown error occured with following error message:</p>" +
				"<div class=\"error\">" + e + "</div>";
			}
		
		
		if( ret==null ) {
			ret = "<p>Your ontology has been successfully imported. Please note that only the following constructs were imported: </p>";
			ret += 
				"<ul>" +
					"<li>owl:Ontology</li>" +
					"<li>owl:Class</li>" +
					"<li>rdfs:Class</li>" +
					"<li>owl:DatatypeProperty</li>" +
					"<li>owl:ObjectProperty</li>" +
				"</ul>";
			
			if( ontologyModuleUri!=null ) {
				try {
				
					ret = "<p>Visit " + Labels.ONTOLOGY.getNameSingular() + " <a href=\"" + HelperFunctions.getUriForHref( ontologyModuleUri ) + "\">" + StringEscapeUtils.escapeHtml( Mapper.selectLabel( ontologyModuleUri, Vocabulary.ENGLISH ) ) + "</a> now.</p>";
				
					
				}
				catch( Exception e ) {
					logger.error( e );
				}
			}
			
			session.setAttribute( "toImportRepository", null );
			session.setAttribute( "HashMap", null );
		}
		else {
			
			session.setAttribute( "toImportRepository", toImportRepository );
			session.setAttribute( "HashMap", hashMap );			
		}
		

		ret = "<newcontent><![CDATA[" + ret + "]]></newcontent>";
		ret += "<focusidafterreceive>newLabelInput</focusidafterreceive>";

		ret = "<importStatusField>" + ret + "</importStatusField>";

		response.setContentType("text/xml;charset=utf-8");
		response.setHeader("Cache-Control", "no-cache");
		response.setCharacterEncoding("UTF-8");
		
	    PrintWriter out = response.getWriter();
	    out.println("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>");
	    out.println( ret );
	    
		
	    session.setAttribute("lockOntology", null);
	    
		try {
			memoryStoreConnection.close();
		}
		catch( Exception e ) {
			logger.error(e);
		}
//		elementLogging.clear();
		elementLogging.finish();
	}   

	// ########################################################################################
	// ########################################################################################
	
	private void importOntologyModule( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, String labelForURI, HashMap<URI, URI> hashMap,AttributeHolder attributes ) throws Exception {
		
		URI uri = importBasics( connection, memoryStoreConnection, toImportUri, labelForURI, Vocabulary.ONTOLOGYMODULE );
		
		hashMap.put( toImportUri, uri ); // wird in session gespeichert und dient dazu, die Referenzen richtig zu setzen (sp�ter)
		markAsImported( memoryStoreConnection, toImportUri );
		connection.commit();
		

		elementLogging.logView(uri, attributes);
//		controller.ElementRanker.RaiseValueOfElement( uri );
		// HelperFunctions.updateClickHistory( Vocabulary.ONTOLOGYMODULE, uri, ActionOnElement.ACTIONCODE_CREATED, session, request.getCookies(), response );
		
	}
	
	private void importClass( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, String labelForURI, HashMap<URI, URI> hashMap, URI ontologyModuleUri,AttributeHolder attributes  ) throws Exception {
		
		URI uri = importBasics( connection, memoryStoreConnection, toImportUri, labelForURI, Vocabulary.CLASS );

		hashMap.put( toImportUri, uri ); // wird in session gespeichert und dient dazu, die Referenzen richtig zu setzen (sp�ter)
		ClassMapper mapper = new ClassMapper();
		
		List<LiteralImpl> flickrImages = selectLiteralObjects(connection, uri, Vocabulary.FLICKRIMAGE);
		String flickrString="";
		if (flickrImages!=null) {
			for (Iterator<LiteralImpl> it = flickrImages.iterator();it.hasNext();) {
				flickrString+=it.next();
				flickrString+=",";
			}
		}
		RepositoryResult<Statement> statements=null;
		try {
		statements = connection.getStatements(uri, null, null, true);
		while (statements.hasNext()){
			Statement st = statements.next();
			String result = st.getObject().stringValue();

		}
		} catch (Exception e) {
			logger.error("error importing class",e);
		}
		finally {
			if (statements!=null)
				try {
					statements.close();
				} catch (RepositoryException e) {
					logger.error(e);
				}
		}
		
		mapper.updateBelongsToOM( connection, uri, HelperFunctions.extractURIs( ontologyModuleUri.stringValue() ), null );
		
		mapper.updateImages(connection, uri, flickrString, null);
		
		markAsImported( memoryStoreConnection, toImportUri );
		connection.commit();

		elementLogging.logView(uri, attributes);
//		controller.ElementRanker.RaiseValueOfElement( uri );
		// HelperFunctions.updateClickHistory( Vocabulary.ONTOLOGYMODULE, uri, ActionOnElement.ACTIONCODE_CREATED, session, request.getCookies(), response );
	}
	
	private void importSubClassOf( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, HashMap<URI, URI> hashMap ) throws Exception {
		
		URI uri = hashMap.get( toImportUri );
		ArrayList<URI> tmp = getSubclassOf( memoryStoreConnection, toImportUri );
		if( tmp!=null ) {

			ClassMapper mapper = new ClassMapper();
			mapper.updateSubclassOf( connection, uri, replaceURIs( tmp, hashMap ), null );
		}
			
		memoryStoreConnection.add( toImportUri, Import.SUBCLASSIMPORTED, new LiteralImpl( "true" ) ); // mark as imported
		memoryStoreConnection.commit();
		connection.commit();
	}
	
	private void importSamePropertyAs( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, HashMap<URI, URI> hashMap ) throws Exception {
		
		URI uri = hashMap.get( toImportUri );
		ArrayList<URI> tmp = getSamePropertyAs( memoryStoreConnection, toImportUri );
		if( tmp!=null ) {

			PropertyMapper mapper = new PropertyMapper();
			mapper.updateSameAs( connection, uri, replaceURIs( tmp, hashMap ), null );
		}
			
		memoryStoreConnection.add( toImportUri, Import.SAMEPROPERTYASIMPORTED, new LiteralImpl( "true" ) ); // mark as imported
		memoryStoreConnection.commit();
		connection.commit();
	}
	
	private void importSameClassAs( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, HashMap<URI, URI> hashMap ) throws Exception {
		
		URI uri = hashMap.get( toImportUri );
		ArrayList<URI> tmp = getSameClassAs( memoryStoreConnection, toImportUri );
		if( tmp!=null ) {

			ClassMapper mapper = new ClassMapper();
			mapper.updateSameAs( connection, uri, replaceURIs( tmp, hashMap ), null );
		}
			
		memoryStoreConnection.add( toImportUri, Import.SAMECLASSASIMPORTED, new LiteralImpl( "true" ) ); // mark as imported
		memoryStoreConnection.commit();
		connection.commit();
	}
	
	private void importProperty( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, String labelForURI, HashMap<URI, URI> hashMap, URI type,AttributeHolder attributes ) throws Exception {
		
		URI uri = importBasics( connection, memoryStoreConnection, toImportUri, labelForURI, type );

		hashMap.put( toImportUri, uri ); // wird in session gespeichert und dient dazu, die Referenzen richtig zu setzen (sp�ter)
		PropertyMapper mapper = new PropertyMapper();

		ArrayList<URI> range = getRange( memoryStoreConnection, toImportUri, type );
		if( range!=null ) {

			mapper.insertRange( connection, uri, replaceURIs( range, hashMap ) );
		}
		
		ArrayList<URI> domain = getDomain( memoryStoreConnection, toImportUri );
		if( domain!=null ) {

			mapper.updateDomain( connection, uri, replaceURIs( domain, hashMap ), null );
		}
		
		
		markAsImported( memoryStoreConnection, toImportUri );
		connection.commit();

		elementLogging.logView(uri, attributes);
//		controller.ElementRanker.RaiseValueOfElement( uri );
		// HelperFunctions.updateClickHistory( Vocabulary.ONTOLOGYMODULE, uri, ActionOnElement.ACTIONCODE_CREATED, session, request.getCookies(), response );
	}

	// ####################################################################################################################
	
	/**
	 * 
	 * @param connection
	 * @param memoryStoreConnection
	 * @param toImportUri
	 * @param labelForURI	is extracted from file OR if exists determined by user
	 * @param type
	 * @return
	 * @throws Exception
	 */
	private URI importBasics( RepositoryConnection connection, RepositoryConnection memoryStoreConnection, URI toImportUri, String labelForURI, URI type ) throws Exception {

		Mapper mapper = new Mapper();
		
		URI uri = null;
		try {
			uri = mapper.createElement(connection, type, labelForURI,false );
		}
		catch( Exception e ) {
			logger.error(e);
		}
		
		if( mapper.exceptionsOccured()==false ) {			

			mapper.insertLabel( connection, uri, labelForURI, Vocabulary.ENGLISH );
			
			ArrayList<LiteralImpl> tmp = getOtherLanguageLabels( memoryStoreConnection, toImportUri, labelForURI );
			if( tmp!=null ) {			
				
				for( LiteralImpl l : tmp ) {

					try {
						// try: so that if the e.g format is not valid this value will not be imported
						
						if( l.getLanguage()!=null && l.stringValue()!=null && !l.stringValue().equals("") )	{
							
							mapper.insertLabel( connection, uri, l.stringValue(), l.getLanguage() );
						}
					}
					catch( Exception e ) {

						logger.error(e);
					}
				}			
			}
						
			String comment = getCommentForElement( memoryStoreConnection, toImportUri );
			
			if( comment!=null && !comment.equals("") ) {
				
				mapper.insertComment( connection, uri, comment, Vocabulary.ENGLISH );
	
				ArrayList<LiteralImpl> tmp2 = getOtherLanguageComments( memoryStoreConnection, toImportUri, comment );
				if( tmp2!=null ) {			
					
					for( LiteralImpl c : tmp2 ) {

						try {
							// try: so that if e.g. format is not valid this value will not be imported

							if( c.getLanguage()!=null && c.stringValue()!=null && !c.stringValue().equals("") )	{	
								
								mapper.insertComment( connection, uri, c.stringValue(), c.getLanguage() );
							}
						}
						catch( Exception e ) {

							logger.error(e);
						}
					}			
				}
			}
			
			
			
			mapper.insertSeeAlso( connection, uri, getSeeAlso( memoryStoreConnection, toImportUri) );
		}
		else {
			ArrayList<Exception> ex = mapper.getExceptionLabel();
			
			throw ex.get(0);
		}

		return uri;
	}


	private void markAsImported( RepositoryConnection memoryStoreConnection, URI uri ) throws Exception {
		
		memoryStoreConnection.add( uri, ELEMENTISIMPORTED, new LiteralImpl( "true" ) ); // mark as imported
		memoryStoreConnection.commit();
	}

	
	private static ArrayList<URI> replaceURIs( ArrayList<URI> list, HashMap<URI, URI> hashMap ) {
		
		ArrayList<URI> ret = null;
		
		if( list!=null ) {
			
			ret = new ArrayList<URI>();
			
			Iterator<URI> iter = list.iterator();
			while( iter.hasNext() ) {
				
				URI tmp = iter.next();

				
				if( tmp.equals( XMLSchema.BOOLEAN ) || tmp.stringValue().equals( "http://www.w3.org/TR/xmlschema-2/#boolean" ) ) {

					ret.add( Vocabulary.XMLSBOOLEAN );
				}
				else if( tmp.equals( XMLSchema.STRING ) || tmp.stringValue().equals( "http://www.w3.org/TR/xmlschema-2/#string" ) ) {

					ret.add( Vocabulary.XMLSSTRING );
				}
				else if( tmp.equals( XMLSchema.INTEGER ) || tmp.stringValue().equals( "http://www.w3.org/TR/xmlschema-2/#integer" ) ) {

					ret.add( Vocabulary.XMLSINTEGER );
				}
				else if( tmp.equals( XMLSchema.DOUBLE ) || tmp.equals( XMLSchema.FLOAT ) || tmp.stringValue().equals( "http://www.w3.org/TR/xmlschema-2/#double" ) || tmp.stringValue().equals( "http://www.w3.org/TR/xmlschema-2/#float" ) ) {

					ret.add( Vocabulary.XMLSDOUBLE );
				}	
				else if( tmp.equals( XMLSchema.DATETIME ) || tmp.stringValue().equals( "http://www.w3.org/TR/xmlschema-2/#dateTime" ) ) {

					ret.add( Vocabulary.XMLSDATETIME );
				}				
				else {
					URI tmp2 = hashMap.get( tmp );
					if( tmp2!=null )
						ret.add( tmp2 );
				}
			}
			
		}
		
		return ret;
	}

	// ########################################################################################


	URI getOntologyUri( RepositoryConnection memoryStoreConnection ) {
		
		URI ret = selectFirstSubject( memoryStoreConnection, RDF.TYPE, OWL.ONTOLOGY );
		
		return ret;
	}
	
	URI getType( RepositoryConnection memoryStoreConnection, URI uri ) {

		URI ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT t FROM {<"+ uri +">} <"+ RDF.TYPE +"> {t} WHERE t=<"+ OWL.CLASS +"> OR t=<"+ RDFS.CLASS +"> OR t=<"+ OWL.OBJECTPROPERTY +"> OR t=<"+ OWL.DATATYPEPROPERTY +"> OR t=<"+ OWL.ONTOLOGY +"> LIMIT 1";
				
				 //System.out.println(query);
				TupleQuery tupleQuery = memoryStoreConnection.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						ret = (URI)result.next().getValue("t");
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
			return null;
		}
		
		return ret;
	}
	
	URI getUnmarkedElement( RepositoryConnection memoryStoreConnection, URI type ) {
		
		URI ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT x FROM {x} <"+ RDF.TYPE +"> {<" + type + ">} MINUS SELECT x FROM {x} <" + Import.ELEMENTISIMPORTED + "> {y}";
				
				 //System.out.println(query);
				TupleQuery tupleQuery = memoryStoreConnection.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						ret = (URI)result.next().getValue("x");
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
			return null;
		}
		
		return ret;
	}
	
	URI getUnmarkedSubClassOf( RepositoryConnection memoryStoreConnection ) {

		URI ret = null;
		
		ret = getUnmarkedField(memoryStoreConnection, RDFS.SUBCLASSOF, SUBCLASSIMPORTED, OWL.CLASS );
		
		if( ret==null )
			ret = getUnmarkedField(memoryStoreConnection, RDFS.SUBCLASSOF, SUBCLASSIMPORTED, RDFS.CLASS );
		
		return ret;
	}
	

	URI getUnmarkedSameClassAs( RepositoryConnection memoryStoreConnection ) {

		URI ret = null;
		
		ret = getUnmarkedField(memoryStoreConnection, OWL.SAMEAS, SAMECLASSASIMPORTED, OWL.CLASS );
		
		if( ret==null )
			ret = getUnmarkedField(memoryStoreConnection, OWL.SAMEAS, SAMECLASSASIMPORTED, RDFS.CLASS );
		
		return ret;
	}
	
	URI getUnmarkedSamePropertyAs( RepositoryConnection memoryStoreConnection ) {
		
		URI ret = null;
		
		ret = getUnmarkedField(memoryStoreConnection, OWL.SAMEAS, SAMEPROPERTYASIMPORTED, OWL.DATATYPEPROPERTY );
		
		if( ret==null )
			ret = getUnmarkedField(memoryStoreConnection, OWL.SAMEAS, SAMEPROPERTYASIMPORTED, OWL.OBJECTPROPERTY );
		
		return ret;
	}
	


	private URI getUnmarkedField( RepositoryConnection memoryStoreConnection, URI property, URI mark, URI type ) {
		
		URI ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT x FROM {x} <"+ property +"> {z}, {x} <" + RDF.TYPE + "> {<"+ type +">} MINUS SELECT DISTINCT x FROM {x} <" + mark + "> {y}";
				
				 //System.out.println(query);
				TupleQuery tupleQuery = memoryStoreConnection.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						ret = (URI)result.next().getValue("x");
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
			return null;
		}
		
		return ret;
	}
	

	
	private String extractLabelOutOfURI( URI uri ) {
		
		String ret = "";
		
		String tmp = uri.stringValue();
		
		if( tmp.contains( "#" ) ) {
			// hash-URI

			ret = tmp.substring( tmp.lastIndexOf('#') + 1 );
		} 
		else {

			// cut last "/"
			if( tmp.charAt( tmp.length()-1 ) == '/') {
				
				tmp = tmp.substring(0, tmp.length()-1);
			}
			
			// extract string after last "/"
			tmp = tmp.substring( tmp.lastIndexOf('/') + 1 );
			
			// cut file-extension (e.g. ".owl")
			if( tmp.contains("."))
				tmp = tmp.substring( 0, tmp.lastIndexOf('.') - 1 );
			
			ret = tmp;
		}
		
		return ret;
	}
	

	/**
	 * Returns the label that is used for the URI and for the label of the created element
	 * @param memoryStoreConnection
	 * @param uri
	 * @return
	 */
	private String getLabelForURI( RepositoryConnection memoryStoreConnection, URI uri ) {

		String ret = selectLiteralObject( memoryStoreConnection, uri, RDFS.LABEL, Vocabulary.ENGLISH );
		
		if( ret==null ) {
			// label will be generated out of URI:
			
			ret = extractLabelOutOfURI( uri );
		}
		
		return ret;
	}

	/**
	 * Returns all labels in other languages than english
	 * @param memoryStoreConnection
	 * @param uri	the uri that contains the labels
	 * @param differentFromLabel	returns only labels that are different from this one
	 * @return
	 */
	private ArrayList<LiteralImpl> getOtherLanguageLabels( RepositoryConnection memoryStoreConnection, URI uri, String differentFromLabel ) {

		ArrayList<LiteralImpl> ret = selectLiteralObjects( memoryStoreConnection, uri, RDFS.LABEL );
				
		if( ret!=null ) {
			
			ArrayList<LiteralImpl> tmp = new ArrayList<LiteralImpl>();
			
			// filter the found values (cut english ones; cut differentFromLabel ones)
			for( LiteralImpl l : ret ) {
				
				if( l.getLanguage()!=null && !l.getLanguage().equals(Vocabulary.ENGLISH) && !l.stringValue().equals(differentFromLabel) ) {
					
					tmp.add( l );
				}
			}
			
			if( tmp.size()==0 )
				tmp = null;
			
			ret = tmp;
		}
		
		return ret;
	}

	/**
	 * Returns the comment that is used for the later created element
	 * @param memoryStoreConnection
	 * @param uri
	 * @return
	 */
	private String getCommentForElement( RepositoryConnection memoryStoreConnection, URI uri ) {
		
		// first try to get an english one:
		String ret = selectLiteralObject( memoryStoreConnection, uri, RDFS.COMMENT, Vocabulary.ENGLISH );
		
		// in nothing found: try to get an other language one:
		if( ret==null )
			ret = selectLiteralObject( memoryStoreConnection, uri, RDFS.COMMENT, null );
		
		return ret;
	}
	

	/**
	 * Returns all comments in other languages than english
	 * @param memoryStoreConnection
	 * @param uri	the uri that contains the comments
	 * @param differentFromComment	returns only comments that are different from this one
	 * @return
	 */
	private ArrayList<LiteralImpl> getOtherLanguageComments( RepositoryConnection memoryStoreConnection, URI uri, String differentFromComment ) {

		ArrayList<LiteralImpl> ret = selectLiteralObjects( memoryStoreConnection, uri, RDFS.COMMENT );
		
		if( ret!=null ) {
			
			ArrayList<LiteralImpl> tmp = new ArrayList<LiteralImpl>();
			
			// filter the found values (cut english ones; cut differentFromLabel ones)
			for( LiteralImpl l : ret ) {
				
				if( l.getLanguage()!=null && !l.getLanguage().equals(Vocabulary.ENGLISH) && !l.stringValue().equals(differentFromComment) ) {
					
					tmp.add( l );
				}
			}
			
			if( tmp.size()==0 )
				tmp = null;
			
			ret = tmp;
		}
		
		return ret;
	}

	private ArrayList<URI> getSeeAlso( RepositoryConnection memoryStoreConnection, URI uri ) {
		
		ArrayList<URI> ret = selectObjects( memoryStoreConnection, uri, RDFS.SEEALSO, null );
		
		return ret;
	}

	private ArrayList<URI> getSubclassOf( RepositoryConnection memoryStoreConnection, URI uri ) {
		
		ArrayList<URI> ret = null;
		
		ArrayList<URI> oc = selectObjects( memoryStoreConnection, uri, RDFS.SUBCLASSOF, OWL.CLASS );
		ArrayList<URI> rc = selectObjects( memoryStoreConnection, uri, RDFS.SUBCLASSOF, RDFS.CLASS );
		if( oc!=null ) {
		
			ret = oc;
			
			if( rc!=null )
				ret.addAll( rc );			
		}
		else {
			ret = rc;
		}
		
		return ret;
	}

	private ArrayList<URI> getSameClassAs( RepositoryConnection memoryStoreConnection, URI uri ) {
		
		ArrayList<URI> ret = null;

		ArrayList<URI> oc = selectObjects( memoryStoreConnection, uri, OWL.EQUIVALENTCLASS, OWL.CLASS );
		ArrayList<URI> rc = selectObjects( memoryStoreConnection, uri, OWL.EQUIVALENTCLASS, RDFS.CLASS );
		if( oc!=null ) {
		
			ret = oc;
			
			if( rc!=null )
				ret.addAll( rc );			
		}
		else {
			ret = rc;
		}
		
		return ret;
	}

	private ArrayList<URI> getSamePropertyAs( RepositoryConnection memoryStoreConnection, URI uri ) {
		
		ArrayList<URI> ret = null;

		ArrayList<URI> dp = selectObjects( memoryStoreConnection, uri, OWL.EQUIVALENTPROPERTY, OWL.DATATYPEPROPERTY );
		ArrayList<URI> op = selectObjects( memoryStoreConnection, uri, OWL.EQUIVALENTPROPERTY, OWL.OBJECTPROPERTY );
		if( dp!=null ) {
		
			ret = dp;
			
			if( op!=null )
				ret.addAll( op );			
		}
		else {
			ret = op;
		}
		
		return ret;
	}

	private ArrayList<URI> getRange( RepositoryConnection memoryStoreConnection, URI uri, URI type ) {

		ArrayList<URI> ret = null;

		try{
			
			try {
				//select all ontologies

				String query = "";

				if( uri==null || type==null )
					return ret;
				else if( type==Vocabulary.OBJECTPROPERTY ) {
					
					query = "SELECT DISTINCT x FROM {<" + uri + ">} <" + RDFS.RANGE + "> {x} RDFS.type {<t>} WHERE t=<"+ OWL.CLASS +"> OR t=<"+ RDFS.CLASS +">";
				}
				else if( type==Vocabulary.DATATYPEPROPERTY ){

					query = "SELECT DISTINCT x FROM {<" + uri + ">} <" + RDFS.RANGE + "> {x} WHERE" +
					" x LIKE \"" + XMLSchema.BOOLEAN + "\" OR x LIKE \"http://www.w3.org/TR/xmlschema-2/#boolean\" OR " +
					" x LIKE \"" + XMLSchema.STRING + "\" OR x LIKE \"http://www.w3.org/TR/xmlschema-2/#string\" OR " +
					" x LIKE \"" + XMLSchema.INTEGER + "\" OR x LIKE \"http://www.w3.org/TR/xmlschema-2/#integer\" OR " +
					" x LIKE \"" + XMLSchema.DOUBLE + "\" OR x LIKE \"http://www.w3.org/TR/xmlschema-2/#double\" OR " +
					" x LIKE \"" + XMLSchema.FLOAT + "\" OR x LIKE \"http://www.w3.org/TR/xmlschema-2/#float\" OR " + // will be replaced to double
					" x LIKE \"" + XMLSchema.DATETIME + "\" OR x LIKE \"http://www.w3.org/TR/xmlschema-2/#dateTime\" LIMIT 1";
					
				}
				else 
					return ret;
					
				//System.out.println( query );
				
				// "SELECT DISTINCT x FROM {x} <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> {type}; <http://www.w3.org/2000/01/rdf-schema#label> {l} WHERE type=<http://myontology.org/v0#Class> AND l LIKE "*bs*" IGNORE CASE LIMIT 10"

				//System.out.println(query);
				TupleQuery tupleQuery = memoryStoreConnection.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();
				try {			
					if( result.hasNext()) {
						ret = new ArrayList<URI>();
						
						while (result.hasNext()) {
							ret.add( (URI)result.next().getValue("x") );
						}
					}
				} finally {
					result.close();
				}
			} finally {
			}
			
		}catch (Exception e) {
			logger.error("Error occoured while selectSubjects: " + e.getMessage());

		}
		
		return ret;	
	}

	private ArrayList<URI> getDomain( RepositoryConnection memoryStoreConnection, URI uri ) {
		
		ArrayList<URI> ret = selectObjects( memoryStoreConnection, uri, RDFS.DOMAIN, OWL.CLASS );
		
		return ret;
	}
	
	// ------------------------

	private static ArrayList<URI> selectObjects( RepositoryConnection con, URI s, URI p, URI type ) {

		ArrayList<URI> ret = null;

		try{
			
			try {
				//select all ontologies

				String query = "";

				if( s==null || p==null )
					return ret;
				
				if (p==null) {
					query = "SELECT DISTINCT x FROM{<"+s.stringValue()+">} {x}";
				}
				if( type!=null)
					query = "SELECT DISTINCT x FROM {<" + s.stringValue() + ">} <" + p.stringValue() + "> {x} RDFS.type {<" + type.stringValue() + ">}";
				else
					query = "SELECT DISTINCT x FROM {<" + s.stringValue() + ">} <" + p.stringValue() + "> {x}";
					
				//System.out.println( query );
				
				// "SELECT DISTINCT x FROM {x} <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> {type}; <http://www.w3.org/2000/01/rdf-schema#label> {l} WHERE type=<http://myontology.org/v0#Class> AND l LIKE "*bs*" IGNORE CASE LIMIT 10"

				//System.out.println(query);
				TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();
				try {			
					if( result.hasNext()) {
						ret = new ArrayList<URI>();
						
						while (result.hasNext()) {
							ret.add( (URI)result.next().getValue("x") );
						}
					}
				} finally {
					result.close();
				}
			} finally {
			}
			
		}catch (Exception e) {
			logger.error("Error occoured while selectSubjects: " + e.getMessage());

		}
		
		return ret;		
	}

	private static URI selectFirstObject( RepositoryConnection con, URI s, URI p ) {
		URI ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT x FROM {<" + s.stringValue() + ">} <"+ p.stringValue()+"> {x} LIMIT 1";
				
				 //System.out.println(query);
				TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						ret = (URI)result.next().getValue("x");
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
		}
		
		return ret;
	}
	private static URI selectFirstSubject( RepositoryConnection con, URI p, URI o  ) {
		URI ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT x FROM {x} <"+ p.stringValue()+"> {<" + o.stringValue() + ">} LIMIT 1";
				
				 //System.out.println(query);
				TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						ret = (URI)result.next().getValue("x");
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
			return null;
		}
		
		return ret;
	}
	
	private static String selectLiteralObject( RepositoryConnection con, URI s, URI p, String lang) {
		String ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT x FROM {<" + s.stringValue() + ">} <"+ p.stringValue()+"> {x} WHERE isLiteral(x) ";
				
				if( lang!=null) {
					query += " AND lang(x)=\"" + lang + "\"";
				}
				
				query += " LIMIT 1";
				
				 //System.out.println(query);
				TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						ret = result.next().getValue("x").stringValue();
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
			return null;
		}
		
		return ret;
	}
	
	private static ArrayList<LiteralImpl> selectLiteralObjects( RepositoryConnection con, URI s, URI p ) {
		ArrayList<LiteralImpl> ret = null;

		try {
			
			try {
				String query = "SELECT DISTINCT x FROM {<" + s.stringValue() + ">} <"+ p.stringValue()+"> {x} WHERE isLiteral(x) ";
								
				 //System.out.println(query);
				TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query);
				TupleQueryResult result = tupleQuery.evaluate();

				try {
					
					if (result.hasNext()) {
						
						ret = new ArrayList<LiteralImpl>();
						
						while (result.hasNext()) {
							
							ret.add( (LiteralImpl)result.next().getValue("x") );
						}
					}
					
				} finally {
					result.close();
				}
			} finally {
			}
			
		} catch (Exception e) {
			logger.error("Error while selecting " + e.getMessage());
			return null;
		}
		
		return ret;
	}
	// ########################################################################################
	// ########################################################################################
	
	private RepositoryConnection getNewConnection( String filePath ) {
		
		RepositoryConnection ret = null;

		// String userPassword = "myontology" + ":" + "myont";
		// String encoding = new sun.misc.BASE64Encoder().encode (userPassword.getBytes());
		
		
		// File dataDir = new File(path);
		Repository myRepository = new SailRepository( new MemoryStore() );
		try {
			myRepository.initialize();
		} catch (Exception exc) {
			logger.error("error during establishing connection to repositroy",exc); 
			
		}
		
		
		try {
			//connect to repository
			ret = myRepository.getConnection();
			
			ret.setAutoCommit(true);
			

			//add data to repository
			//java.net.URL url = new java.net.URL( filePath );
			//URLConnection u = url.openConnection();	
			// u.setRequestProperty ("Authorization", "Basic " + encoding);	
			//u.setDoInput(true);
			
			File myfile = new File( filePath );
			ret.add( myfile, "", RDFFormat.RDFXML);
		}
		catch( Exception e ) {
			logger.error( e );

		}
		
		return ret;
	}
}
